package org.zhu.steam;

import org.zhu.LamadaInterface.myclass.Bar;
import org.zhu.LamadaInterface.myclass.Foo;
import org.zhu.LamadaInterface.myclass.Person2;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Supplier;
import java.util.stream.*;

/**
 * Created by zhu yingzhi on 2017/9/12.
 * java8 steam 操作
 */
public class Client {

    public static void main(String[] args) throws IOException {


        parallelStream();
    }


    /**
     * 并行流练习
     */
    private static void parallelStream(){
        //查看公公线程池的默认线程数
        ForkJoinPool commonPool = ForkJoinPool.commonPool();
        System.out.println(commonPool.getParallelism());
        //
        List<Person2> persons =
                Arrays.asList(
                        new Person2("zhu",1),new Person2("yang",2),new Person2("yang",3),new Person2("yang",3),
                        new Person2("wang",3),new Person2("liu",5),new Person2("zhang",3));
        System.out.println("并行流:");
        persons.parallelStream().
                filter((s)->{System.out.format("filter:%s 线程池名字为：%s\n",s.getName(),Thread.currentThread().getName());return true;})
                .peek(s-> System.out.format("map:%s 线程池名字为：%s\n",s.getName(),Thread.currentThread().getName()))
                .forEach(s-> System.out.format("forEach:%s 线程池名字为：%s\n",s.getName(),Thread.currentThread().getName()));
        System.out.println("单线程流:");
        persons.stream().
                filter((s)->{System.out.format("filter:%s 线程池名字为：%s\n",s.getName(),Thread.currentThread().getName());return true;})
                .peek(s-> System.out.format("map:%s 线程池名字为：%s\n",s.getName(),Thread.currentThread().getName()))
                .forEach(s-> System.out.format("forEach:%s 线程池名字为：%s\n",s.getName(),Thread.currentThread().getName()));
    }
    /**
     * reduce 练习
     */
    private static void reduceTest(){
        List<Person2> persons =
                Arrays.asList(
                        new Person2("zhu",1),new Person2("yang",2),new Person2("yang",3),new Person2("yang",3),
                        new Person2("wang",3),new Person2("liu",5),new Person2("zhang",3));

        //多态方法1参数 把所有的参数作为比较
       persons.stream().reduce((p1,p2)-> p1.getAge()>p2.getAge()?p1:p2).ifPresent(System.out::println);

       //多态方法2参数 把所有的List与申明的特定参数做比较
        System.out.println(persons.stream().reduce(new Person2("liao",7),(p1,p2)-> p1.getAge()>p2.getAge()?p1:p2).getName());

        //多态方法3参数 对任意类型的参数做出比较
        System.out.println(persons.stream().reduce(0,  (sum, p) -> {
                    System.out.format("accumulator: sum=%s; person=%s\n", sum, p);
                    return sum += p.getAge();
                },
                (sum1, sum2) -> {
                    System.out.format("combiner: sum1=%s; sum2=%s\n", sum1, sum2);
                    return sum1 + sum2;
                }));
    }

    /**
     * flatMap 练习 map主要是返回的固定的一个元素 而flatMap返回0或者多个元素
     */
    private static void flatMapTest(){

        IntStream.range(1,4).
                mapToObj((s)-> new Foo("foo"+s)).
                peek((f->f.bars=IntStream.range(1,6).mapToObj((s)->new Bar(f.name+"bar"+s)).collect(Collectors.toList())))
                .flatMap(f->f.bars.stream())
                .forEach(b->System.out.println(b.name));
    }

    /**
     * collect 收集器
     */
     static void collectTest(){
        //通过年龄进行分组
        List<Person2> persons =
                Arrays.asList(
                        new Person2("zhu",1),new Person2("yang",2),new Person2("yang",3),new Person2("yang",3),
                        new Person2("wang",3),new Person2("liu",1),new Person2("zhang",3));
        Map<Integer,List<Person2>> person2Map = persons.stream()
                .collect(Collectors.groupingBy(Person2::getAge));
        person2Map.forEach((k,v)-> System.out.format("年龄:%s 人数：%s\n",k,v.size()));
        //计算年龄的平均值
        Double average = persons.stream().collect(Collectors.averagingInt(Person2::getAge));
        System.out.format("年龄平均值%f\n",average);

        //收集所得数据的 这些类型count, min, max, sum, and average.
        IntSummaryStatistics summaryStatistics = persons.stream().collect(Collectors.summarizingInt(Person2::getAge));
        System.out.format("最大值：%s 最小值：%s 平均值：%s 总数：%s\n",summaryStatistics.getMax(),summaryStatistics.getMin(),
                summaryStatistics.getAverage(),summaryStatistics.getSum());

        //Stream 系列之字符串得拼接
        String str = persons.stream().map(Person2::getName).
                collect(Collectors.joining(" 和 ", "三策科技程序员 ", " 是最帅的.\n"));
        System.out.println(str);
        //Stream之 转化成为Map 如果有相同的元素的话 则可以选择对相同的键值中的元素进行操作
        Map<String, Integer> map = persons.stream().
                collect(Collectors.toMap(Person2::getName,Person2::getAge,(name1,name2)->name1+name2));
        System.out.println(map);
        //自定义Collector 用于把流中得字符按特定的分隔符进行组合
        Collector<Person2,StringJoiner,String> stringCollector = Collector.of(()->new StringJoiner("!"),(s,p)->s.add(p.getName()), StringJoiner::merge,StringJoiner::toString);
        System.out.println(persons.stream().collect(stringCollector));
    }

    /**
     * 重用流 同一个流不能重用
     */
    public static void reUseStream(){
        Stream<String> stream =
                Stream.of("d2", "a2", "b1", "b3", "c")
                        .filter(s -> s.startsWith("a"));

        stream.anyMatch(s -> true);    // ok
//        stream.noneMatch(s -> true);   // exception
        Supplier<Stream<String>> streamSupplier =
                () -> Stream.of("d2", "a2", "b1", "b3", "c")
                        .filter(s -> s.startsWith("a"));

        streamSupplier.get().anyMatch(s -> true);   // ok
        streamSupplier.get().noneMatch(s -> true);

    }

    /**
     * 深入理解处理流的过程 stream处理是按链式来进行操作 除了中间操作sort
     */
    private static void orderProcess(){
        //Stream的中间操作 只有在结束此stream链时才会执行
        Stream.of("d2", "a2", "b1", "b3", "c")
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return true;
                });

        //Stream 遍历元素是通过，Stream的方法 不是水平移动 而是上下沿着Stream链条 遍历垂直移动
        Stream.of("d2", "a2", "b1", "b3", "c")
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return true;
                }).forEach(s -> System.out.println("forEach: " + s));
        //因为操作是沿着Stream链条遍历垂直移动 所以到了A2的时候为True 不进行下一步操作
        Stream.of("d2", "a2", "b1", "b3", "c")
                .map(s -> {
                    System.out.println("map: " + s);
                    return s.toUpperCase();
                })
                .anyMatch(s -> {
                    System.out.println("anyMatch: " + s);
                    return s.startsWith("A");
                });
        //通过如下的两个例子可以发现 中间操作的放置顺序可以决定执行的结果
        Stream.of("d2", "a2", "b1", "b3", "c")
                .map(s -> {
                    System.out.println("map: " + s);
                    return s.toUpperCase();
                })
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return s.startsWith("A");
                })
                .forEach(s -> System.out.println("forEach: " + s));

        Stream.of("d2", "a2", "b1", "b3", "c")
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return s.startsWith("a");
                })
                .map(s -> {
                    System.out.println("map: " + s);
                    return s.toUpperCase();
                })
                .forEach(s -> System.out.println("forEach: " + s));

        //对于sort操作 sort操作不同于 其他中间操作 sort操作不是链式执行 而是水平执行 执行完后这个循环才给下一个中间操作
        Stream.of("d2", "a2", "b1", "b3", "c")
                .sorted((s1, s2) -> {
                    System.out.printf("sort: %s; %s\n", s1, s2);
                    return s1.compareTo(s2);
                })
                .filter(s -> {
                    System.out.println("filter: " + s);
                    return s.startsWith("a");
                })
                .map(s -> {
                    System.out.println("map: " + s);
                    return s.toUpperCase();
                })
                .forEach(s -> System.out.println("forEach: " + s));
    }

    /**
     * 通过list 创建流
     */
    private static void listStreamTest(){

        List<String> mylist = Arrays.asList("zhu","wang","liu","yang","zhang");
        List<String> list2 = mylist.stream()
                .filter(s->s.startsWith("z"))
                .map(String::toUpperCase)
                .sorted()
                .collect(Collectors.toList());

        list2.forEach(System.out::print);
        mylist.forEach(System.out::print);
    }

    /**
     * 通过Stream默认的方法创建流
     */
    private static void defaultSteamTest(){

        Stream.of("zhu","wang","liu","yang","zhang","yan")
                .filter(s->s.startsWith("y"))
                .findFirst()
                .ifPresent(System.out::print);

        System.out.println(IntStream.range(1,10)
                .anyMatch((s)-> s>5));

        //IntStream 范围函数
        IntStream.range(1,10)
                .mapToObj((n)->n+"heahd")
                .forEach(System.out::print);

        //double 转int 再转对象
        DoubleStream.of(1.5,2.6,3.7)
                .mapToInt(s->(int) Math.ceil(s))
                .mapToObj(s->s+"meme")
                .forEach(System.out::print);
    }


}
